#ifndef __FG__COROUTINE__MANAGER__H__
#define __FG__COROUTINE__MANAGER__H__

#include <thread>
#include <vector>
#include <list>
#include <iostream>

#ifdef __APPLE__
#define _XOPEN_SOURCE
#endif

//#define NF_TEST

#ifdef FG_TEST
#define FG_PLATFORM_WIN 1
#define FG_PLATFORM_LINUX 2
#define FG_PLATFORM_APPLE 3

#define  FG_PLATFORM NF_PLATFORM_APPLE

//millisecond
inline int64_t GetTimeMS()
{
    return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}

typedef void (* CoroutineFunction)(void* arg);
#else
#include "PluginModule/IModule.h"
#include "Core/Singleton.hpp"
#endif

#if FG_PLATFORM != FG_PLATFORM_WIN
#include <ucontext.h>
#endif

#ifdef _DEBUG
#define MAX_COROUTINE_STACK_SIZE (1024 * 512)
#define MAX_COROUTINE_CAPACITY   (128 * 1)
#else
#define MAX_COROUTINE_STACK_SIZE (1024 * 512)
#define MAX_COROUTINE_CAPACITY   (1024 * 1)
#endif

namespace FragrantGrass
{
	enum CoroutineState
	{
		FREE,
		SUSPEND
	};

	class Coroutine;
	class CoroutineManager;

	class Coroutine
	{
	public:
		Coroutine(CoroutineManager* p, int id)
		{
			pSchdule = p;
			state = CoroutineState::FREE;
			nID = id;
			nYieldTime = 0;
		}

		CoroutineFunction func;
		int64_t nYieldTime;
		void* arg;
		enum CoroutineState state;
		int nID;
		CoroutineManager* pSchdule;

#if FG_PLATFORM != FG_PLATFORM_WIN
		ucontext_t ctx;
#endif
		char stack[MAX_COROUTINE_STACK_SIZE];
	};

	class CoroutineManager
	{
	public:

		CoroutineManager();

		virtual ~CoroutineManager();

		void Init(CoroutineFunction func);

		void RemoveRunningID(int id);

		void YieldCo();

		void YieldCo(const int64_t nSecond);

		void ScheduleJob();

	protected:
		void NewMainCoroutine();

		void Resume(int id);

		Coroutine* AllotCoroutine();

		Coroutine* GetCoroutine(int id);
		Coroutine* GetRunningCoroutine();

	protected:
		CoroutineFunction mxMainFunc;
		void* mpMainArg;

#if FG_PLATFORM != FG_PLATFORM_WIN
		ucontext_t mxMainCtx;
#endif
		int mnRunningCoroutineID;
		int mnMainID;

		std::vector<Coroutine*> mxCoroutineList;
		std::list<int> mxRunningList;
	};
}

#endif//__FG__COROUTINE__MANAGER__H__